import { Vec3 } from 'cc';

const _vab = /*@__PURE__*/ new Vec3();
const _vac = /*@__PURE__*/ new Vec3();
const _vap = /*@__PURE__*/ new Vec3();
const _vbp = /*@__PURE__*/ new Vec3();
const _vcp = /*@__PURE__*/ new Vec3();
const _vbc = /*@__PURE__*/ new Vec3();
/* 移植自Three.js */
export class Triangle{
 
    constructor(public a=new Vec3(),public b=new Vec3(),public c=new Vec3()) {
        this.c = c;
        this.b = b;
        this.a = a;
    }
    set( a:Vec3, b:Vec3, c:Vec3 ):Triangle {
		this.a.set( a );
		this.b.set( b );
		this.c.set( c );
		return this;
	}

    closestPointToPoint( p:Vec3, target:Vec3 ):Vec3 {
		const a = this.a, b = this.b, c = this.c;
		let v, w;
		// algorithm thanks to Real-Time Collision Detection by Christer Ericson,
		// published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc.,
		// under the accompanying license; see chapter 5.1.5 for detailed explanation.
		// basically, we're distinguishing which of the voronoi regions of the triangle
		// the point lies in with the minimum amount of redundant computation.
		Vec3.subtract( _vab,b, a );
        Vec3.subtract( _vac,c, a );
        Vec3.subtract( _vap,p, a );
		const d1 = _vab.dot( _vap );
		const d2 = _vac.dot( _vap );
		if ( d1 <= 0 && d2 <= 0 ) {
			// vertex region of A; barycentric coords (1, 0, 0)
			return target.set(a.clone());
		}
        Vec3.subtract( _vbp,p, b );
		const d3 = _vab.dot( _vbp );
		const d4 = _vac.dot( _vbp );
		if ( d3 >= 0 && d4 <= d3 ) {
			// vertex region of B; barycentric coords (0, 1, 0)
			return target.set(b.clone());
		}
		const vc = d1 * d4 - d3 * d2;
		if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) {
			v = d1 / ( d1 - d3 );
			// edge region of AB; barycentric coords (1-v, v, 0)
			return target.set(a.clone().add(_vab.multiplyScalar(v)))

		}
        Vec3.subtract( _vcp,p, c );
		const d5 = _vab.dot( _vcp );
		const d6 = _vac.dot( _vcp );
		if ( d6 >= 0 && d5 <= d6 ) {
			// vertex region of C; barycentric coords (0, 0, 1)
			return target.set(c);
		}

		const vb = d5 * d2 - d1 * d6;
		if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) {
			w = d2 / ( d2 - d6 );
			// edge region of AC; barycentric coords (1-w, 0, w)
			return target.set(a.add(_vac.multiplyScalar(w)));

		}

		const va = d3 * d6 - d5 * d4;
		if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) {
            Vec3.subtract( _vbc,c, b );
			w = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) );
			// edge region of BC; barycentric coords (0, 1-w, w)
			return  target.set(b.add(_vbc.multiplyScalar(w))); // edge region of BC
		}
		// face region
		const denom = 1 / ( va + vb + vc );
		// u = va * denom
		v = vb * denom;
		w = vc * denom;
		return  target.set(a.add(_vab.multiplyScalar(v)).add(_vac.multiplyScalar(w)));

	}
}

